package network;

import ihm.MainFrame;
import ihm.panel.BMPPlayer;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;

import cipher.algorithm.Algorithm;
import cipher.algorithm.Empty;
import cipher.module.Cipher_;
import cipher.module.Cipher_Thread_Manager;

import tools.TCPUtils;

public class KrakenClient extends Thread {

	private static final int DEFAULT_PORT_NUMBER = 18000;
	private Socket socket;
	private BufferedReader in;
	private PrintWriter out;
	private String servName;
	private String final_answer;
	private ArrayList<String> message_list;
	private boolean finished;
	
	private byte[] header;
	private byte[] data;
	private byte[] data_d;
	
	private BMPPlayer player;
	private MainFrame mainFrame;
	private Algorithm algo = new Empty();
	private static int MODE = 0;
    private final Object lock = new Object(), lock2 = new Object();
    
	
	public KrakenClient(String nameServer, BMPPlayer player, MainFrame mainFrame) {
		this.socket = null;
		this.in = null;
		this.out = null;
		this.servName = nameServer;
		this.final_answer = "";
		this.finished = false;
		this.player = player;
		this.mainFrame = mainFrame;
	}
	
	public KrakenClient(ArrayList<String> msg, String nameServer) {
		this.socket = null;
		this.in = null;
		this.out = null;
		this.servName = nameServer;
		this.final_answer = "";
		this.message_list = msg;
		this.finished = false;
	}
	
	public void connect() {
		try {
			socket = new Socket(servName, DEFAULT_PORT_NUMBER);
			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			out = new PrintWriter(socket.getOutputStream(),true);
		} catch (UnknownHostException e1) {
			e1.printStackTrace();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
	}
	
	public void disconnect() {
		finished = true;
	}
	
	public String sendMessage(String msg) {
		String answer = "";
		//envoie le message au serveur
		out.println(msg);
		out.flush();
		try{
			//réceptionne la réponse
			answer = in.readLine();
			//System.out.println("Reponse du serveur"+answer);
	    } catch (IOException e2){
	    	System.out.println("Read failed "+e2);
	    	System.exit(1);
	    }
		
        return answer;
	}
	
	public void sendMessage_noAnwser(String msg) {
		out.println(msg);
		out.flush();
	}
	
	public void communicate() {
		int i = 0;
		String state = "";
		String msgCmd[];
		while(!finished) {
			System.out.println("i = "+i+" et size "+message_list.size());
			System.out.println(message_list.get(i));
			state = sendMessage(message_list.get(i));
			System.out.println("rep serv : "+state); //Debug
			msgCmd = state.split("  ");
			
			// recepteur
			
			// connecté au serveur
			if(msgCmd[0].equalsIgnoreCase(KrakenServerMsg.CIPHER_SERVER.toString())) {
				System.out.println("Connexion au serveur réussie");
			}
			
			// reception de l'entête
			else if(msgCmd[0].equalsIgnoreCase(KrakenServerMsg.SEND_HEADER.toString())) {
				System.out.println("Je receptionne l'entête des images");
				try {
					header = TCPUtils.tcpWaitingData_(socket);
					//header_size = header.length;
					//System.arraycopy(header, 0, bmp, 0, header_size);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			// reception d'un flux
			else if(msgCmd[0].equalsIgnoreCase(KrakenServerMsg.SEND_FLUX.toString())) {
				System.out.println("Je receptionne un flux");
				while(true) {
					try {
						// attend le prochain SEND_DATA du serveur
						state = in.readLine();
						if(state.equals(KrakenServerMsg.END_SERVER.toString())) break;
						/*synchronized (lock2) {
							
							if(state.equalsIgnoreCase(KrakenServerMsg.SEND_KEY.toString())){
								msgCmd = state.split("  ");
								this.mainFrame.getKeyField1().setText(msgCmd[1]);
								this.mainFrame.getKeyField2().setText(msgCmd[2]);
							}
						}*/
							if(state.equalsIgnoreCase(KrakenServerMsg.SEND_DATA.toString())){
								//synchronized (lock) {
									data = TCPUtils.tcpWaitingData(socket);
									//data_d = Cipher_Thread_Manager.chiffrement(algo, data, MODE, 4);
									//System.out.println(data[15000]+" "+data_d[15000]);
								//}
								
								if(data != null) {
									//synchronized (lock) {
										data_d = Cipher_.chiffrement(algo, data, MODE);
									//}
									//synchronized (lock) {
										player.nextFrame(header, data_d);
									//}
								}
								
								out.println(KrakenClientMsg.WAITING_NEXT_FRAME.toString());
								out.flush();
							}
						//}
					} catch (Exception e) {
						e.printStackTrace();
						
						mainFrame.refreshClientInfos();
						connect();
						communicate();
						
						//return;
					}
				}
			}
			
			// reception d'une image
			else if(msgCmd[0].equalsIgnoreCase(KrakenServerMsg.SEND_DATA.toString())) {
				System.out.println("Je receptionne une image");
				try {
					data = TCPUtils.tcpWaitingData(socket);
					//System.arraycopy(data, 0, bmp, header_size, data.length);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
			//bon déroulement de fin
			else if(msgCmd[0].equalsIgnoreCase(KrakenServerMsg.END_SERVER.toString())){
				this.final_answer = state;
				finished = true;
			}
			//problème
			else if(msgCmd[0].equalsIgnoreCase(KrakenServerMsg.TIMEOUT.toString())){
				this.final_answer = KrakenServerMsg.TIMEOUT.makeCommand(" "+message_list.get(i));
				finished = true;
			}
			else if(msgCmd[0].equalsIgnoreCase(KrakenServerMsg.ERROR.toString())){
				this.final_answer = KrakenServerMsg.ERROR.makeCommand(" "+message_list.get(i));
				finished = true;
			}
			else if(msgCmd[0].equalsIgnoreCase(KrakenServerMsg.UNKNOWN_COMMAND.toString())){
				this.final_answer = KrakenServerMsg.UNKNOWN_COMMAND.makeCommand(" "+message_list.get(i));
				finished = true;
			}
			//pas de fin "normale" = pas de CLIENT_END envoyé au serveur...
			else if(i == message_list.size()){
				this.final_answer = KrakenServerMsg.ERROR.makeCommand(" NO_END_SENT");
				finished = true;
			}
			i++;
		}
	}
	
	public ArrayList<String> getMessages() { return this.message_list; }
	public void setMessage_list(ArrayList<String> message_list) { this.message_list = message_list; }
	
	public String getFinalAnswer() { return this.final_answer; }
	
	/*public int getHeader_size() { return header_size; }
	public void setHeader_size(int header_size) { this.header_size = header_size; }
	
	public int getData_size() { return data_size; }
	public void setData_size(int data_size) { this.data_size = data_size; }*/

	public byte[] getHeader() { return header; }
	public void setHeader(byte[] header) { this.header = header; }

	public byte[] getData() { return data; }
	public void setData(byte[] data) { this.data = data; }
	
	public Algorithm getAlgo() { return algo; }
	public void setAlgo(Algorithm algo) { this.algo = algo; }

	public static int getMODE() { return MODE; }
	public static void setMODE(int mODE) { MODE = mODE; }

	@Override
	public void run() {
		ArrayList<String> msg = new ArrayList<String>();
		msg.add(KrakenClientMsg.CIPHER_CLIENT.toString());
		msg.add(KrakenClientMsg.WAITING_HEADER.toString());
		//msg.add(KrakenClientMsg.WAITING_DATA.toString());
		msg.add(KrakenClientMsg.WAITING_FLUX.toString());
		msg.add(KrakenClientMsg.END_CLIENT.toString());
		setMessage_list(msg);
		connect();
		communicate();
	}
	
}
